<?php

namespace app\common\services;

use app\common\services\DecryptException;

class RSAAESDecrypter
{
    /**
     * AES加密算法名
     * 需要和前端配合
     *
     * @var string
     */
    protected $cipher = 'aes-128-cbc';

    /**
     * RSA服务器私钥
     *
     * @var resource
     */
    protected $rsaPrivateKey;

    /**
     * 创建一个新RSAAESDecrypter实例
     *
     * @param  string  $key
     * @param  string  $cipher
     *
     * @throws DecryptException
     */
    public function __construct(string $rsaPrivateKeyPath)
    {
        $this->rsaPrivateKey = $this->readPrivateKey($rsaPrivateKeyPath);
    }

    /**
     * AES加密给定值
     *
     * @param  mixed  $value
     * @return string
     *
     * @throws DecryptException
     */
    public function aesEncrypt($key, $iv, $value)
    {
        $encrypted = openssl_encrypt($value, $this->cipher, $key, 0, $iv);
        if ($encrypted === false) {
            throw new DecryptException('Can\'t aes encrypt the data.');
        }
        return $encrypted;
    }

    /**
     * AES解密给定值
     *
     * @param  mixed  $payload
     * @return mixed
     *
     * @throws DecryptException
     */
    public function aesDecrypt($key, $iv, $payload)
    {
        // use OPENSSL_ZERO_PADDING
        $original = openssl_decrypt($payload, $this->cipher, $key, 0 , $iv);
        if ($original === false) {
            throw new DecryptException('Can\'t aes decrypt the data.');
        }
        return $original;
    }

    /**
     * 读取并返回私钥内容
     *
     * @param string $path 私钥路径
     *
     * @throws DecryptException
     */
    protected function readPrivateKey($path)
    {
        // 读取私钥内容
        $privateKeyContent = file_get_contents($path);
        $privateKeyResource = openssl_pkey_get_private($privateKeyContent);
        if ($privateKeyResource === false) {
            throw new DecryptException('RSA Key invalid.');
        }

        return $privateKeyResource;
    }

    /**
     * RSA解密给定值
     *
     * @param  mixed  $payload
     * @return mixed
     *
     * @throws DecryptException
     */
    public function rsaDecrypt($payload)
    {
        $encrypted = base64_decode($payload);
        // 私钥解密
        $flag = openssl_private_decrypt($encrypted, $decrypted, $this->rsaPrivateKey);
        // 异常处理
        if ($flag === false) {
            throw new DecryptException('Could not rsa decrypt the data.');
        }
        // 返回结果
        return $decrypted;
    }

    /**
     * 通过RSA-AES组合算法，使用enkey和iv解密payload为原始数据value
     *
     * @param string $enkey    加密后的key
     * @param string $iv       随机初始化向量
     * @param string $payload  加密后的数据
     *
     * @return string 解密后的value
     * @throws DecryptException
     */
    public function decrypet($enkey, $iv, $payload)
    {
        $key = $this->rsaDecrypt($enkey);

        $value = $this->aesDecrypt($key, $iv, $payload);

        return $value;
    }
}
